"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""
from random import choice

from django.contrib.auth.models import User
from django.test import TestCase
from django.utils import simplejson as json
from django.utils.timezone import now

from malachite.models import Post, Tag


class BasePostsTests(TestCase):
    ADMIN_USERID = ADMIN_PASSWD = 'admin'

    def _create_and_save_tags(self):
        """Create a number of tags as fixtures"""
        tag_names = ['foos', "bars"]
        for name in tag_names:
            tag = Tag()
            tag.name = name
            tag.save()

    def _create_and_save_posts(self):
        """Just create one post as a fixture"""
        post_title = "Foo bar"
        post = Post()
        post.title = post_title
        post.creator = self.fake_admin
        post.body = "<em>hello, world!</em>"
        post.save()

    def admin_login(self):
        self.client.login(username='admin', password='admin')

    def admin_logout(self):
        self.client.logout()

    def setUp(self):
        self.fake_admin = User._default_manager.create_user(
            self.ADMIN_USERID, "admin@example.com", password=self.ADMIN_PASSWD
        )
        self._create_and_save_tags()
        self._create_and_save_posts()

    def tearDown(self):
        self.fake_admin.delete()


class BasicUserTests(BasePostsTests):
    def test__login_logout(self):
        """
        Check the correctness of the context processor added tag 'is_logged_in'
        """

        def _check_logged_in():
            resp_ = self.client.get('/blog/posts/')
            return resp_.context[0].get('is_logged_in', None)

        self.assertFalse(_check_logged_in())
        self.admin_login()
        self.assertTrue(_check_logged_in())


class BasicPostsTests(BasePostsTests):
    """Basic Integration Tests"""

    def test__tags_created(self):
        tags = Tag.objects.all()
        self.assertTrue(len(tags) > 0)

    def test__create_and_save_post(self):
        post_title = "Bar Foo"

        post = Post()
        post.title = post_title
        post.creator = self.fake_admin
        post.body = "<em>hello again!</em>"
        post.published = now()

        post.save()

        random_tag = choice(Tag.objects.all())
        post.tags.add(random_tag)

        posts = Post.objects.filter(title=post_title)
        this_post = posts[0]

        self.assertEquals(this_post.title, post_title)

    def test__visible_queryset(self):
        """Test the all_visible method on the custom queryset"""
        # Get posts
        posts = Post.objects.all()
        self.assertTrue(posts.count())
        self.assertTrue(posts.published().count() == 0)
        # Select one post and change its status
        post = posts[0]
        post.published = now()
        post.save()
        # Get a fresh queryset
        del posts
        posts = Post.objects.all()
        # Now test the condition
        self.assertTrue(posts.published().count() == 1)

    def test__verbose_name(self):
        """Test that verbose names are set correctly"""
        for fld in Post._meta.fields:
            if fld.name == "modified":
                self.assertEquals(fld.verbose_name, u"Last modified")


class PostsViewsTests(BasePostsTests):
    """Tests for Posts views"""

    def test__post_list_html_view(self):
        # Return a list of posts
        response = self.client.get('/blog/posts/')

        # Resource exists
        self.assertEquals(response.status_code, 200)

        # base.html and posts_list.html are rendered
        tmpl_list = [t.name for t in response.templates]
        self.assertTrue("base.html" in tmpl_list and\
                        "posts_list.html" in tmpl_list)

        # None should be visible to anonymous
        #for title in [p.title for p in Post.objects.all().all_hidden()]:
        #    self.assertFalse(title in response.content)

        self.admin_login()

        response = self.client.get('/blog/posts/')
        # All should be visible to authenticated user
        for title in [p.title for p in Post.objects.all()]:
            try:
                self.assertTrue(title in response.content)
            except AssertionError, e:
                raise AssertionError, (
                    ("%s " % e) +
                    "(Suggestion: Add the "
                    "'malachite.processor.is_logged_in' context processor"
                    "to you settings.py)"
                    )

    def test__post_list_json_view(self):
        """Test fot a lists of posts represented using a JSON content type"""
        response = self.client.get('/blog/posts/',
                                   HTTP_ACCEPT="application/json")
        data = json.loads(response.content)
        # Unauthenticated sees no posts
        self.assertEquals(len(data), 0)

        self.admin_login()

        response = self.client.get('/blog/posts/',
                                   HTTP_ACCEPT="application/json")
        data = json.loads(response.content)
        # Authenticated should see one
        self.assertTrue(isinstance(data, list))
        self.assertTrue(isinstance(data[0], dict))


